<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>JS 防抖节流</title>
    <link href="https://cdn.staticfile.org/highlight.js/9.15.6/styles/github.min.css" rel="stylesheet">
    <script src="https://cdn.staticfile.org/highlight.js/9.15.6/highlight.min.js"></script>
    <style>
        button, span {
            font-size: 18px;
        }
    </style>
</head>
<body>
<span id="sp0">0</span>
<br>
<button id="bt0">不限制</button>
<br>
<span id="sp1">0</span>
<br>
<button id="bt1">防抖(点完必须停1秒以上不点)</button>
<br>
<span id="sp2">0</span>
<br>
<button id="bt2">节流(点完1秒无反应)</button>
<br>
<pre>
    <code>/**
 * 防抖核心代码
 * 逻辑是
 * 第一次点完以后开始计时
 * 如果单位时间内点了的话
 * 不但无效，而且时间从头计算
 *
 * 例如
 * 设置3000毫秒
 * 第一次点完如果3秒内再次点击
 * 不但不触发任何效果，而且3秒从头开始算
 * 如果一直点一直点，就永远无效
 */
function debounce(fn, timer) {
    let timeout = null;
    return function () {
        if (timeout) {
            clearTimeout(timeout);
        } else {
            fn.apply(this, arguments);
        }
        timeout = setTimeout(() => {
            timeout = null;
        }, timer);
    }
}


/**
 * 节流核心代码
 * 逻辑是
 * 第一次点完以后开始计时
 * 如果下次点击时间没达到设定时间
 * 则无效，否则有效
 *
 * 例如
 * 设置3000毫秒
 * 第一次点击完过了1秒点击 判定为无效 立刻记录当前时间
 * 过了2秒点击 与上一次时间对比 不足3秒 判定无效
 * 过了3秒以上点击 与上次时间对比 足够3秒 判定有效 并立刻记录当前时间
 *
 */
function throttle(fn, delay) {
    let begin = 0;
    return function () {
        const current = new Date().getTime();
        if (current - begin > delay) {
            fn.apply(this, arguments);
            begin = current;
        }
    }
}

/** 简单例子 */
bt0.addEventListener('click', click0, false);
bt1.addEventListener('click', debounce(click1, 1000), false);
bt2.addEventListener('click', throttle(click2, 1000), false);</code>
</pre>
<script>
    hljs.initHighlightingOnLoad();
    /*
     * 本页面并非原创，仅为学习笔记
     * 学习自视频 https://www.bilibili.com/video/BV1Vy4y1y7tj
     */

    let c0 = c1 = c2 = 0;
    const sp0 = document.querySelector('#sp0');
    const bt0 = document.querySelector('#bt0');
    const sp1 = document.querySelector('#sp1');
    const bt1 = document.querySelector('#bt1');
    const sp2 = document.querySelector('#sp2');
    const bt2 = document.querySelector('#bt2');

    bt0.addEventListener('click', click0, false);
    bt1.addEventListener('click', debounce(click1, 1000), false);
    bt2.addEventListener('click', throttle(click2, 1000), false);

    function click0() {
        sp0.innerText = ++c0;
    }

    function click1() {
        sp1.innerText = ++c1;
    }

    function click2() {
        sp2.innerText = ++c2;
    }

    /**
     * 防抖核心代码
     * 逻辑是
     * 第一次点完以后开始计时
     * 如果单位时间内点了的话
     * 不但无效，而且时间从头计算
     *
     * 例如
     * 设置3000毫秒
     * 第一次点完如果3秒内再次点击
     * 不但不触发任何效果，而且3秒从头开始算
     * 如果一直点一直点，就永远无效
     */
    function debounce(fn, timer) {
        let timeout = null;
        return function () {
            if (timeout) {
                clearTimeout(timeout);
            } else {
                fn.apply(this, arguments);
            }
            timeout = setTimeout(() => {
                timeout = null;
            }, timer);
        }
    }

    /**
     * 节流核心代码
     * 逻辑是
     * 第一次点完以后开始计时
     * 如果下次点击时间没达到设定时间
     * 则无效，否则有效
     *
     * 例如
     * 设置3000毫秒
     * 第一次点击完过了1秒点击 判定为无效 立刻记录当前时间
     * 过了2秒点击 与上一次时间对比 不足3秒 判定无效
     * 过了3秒以上点击 与上次时间对比 足够3秒 判定有效 并立刻记录当前时间
     *
     */
    function throttle(fn, delay) {
        let begin = 0;
        return function () {
            const current = new Date().getTime();
            if (current - begin > delay) {
                fn.apply(this, arguments);
                begin = current;
            }
        }
    }
</script>
</body>
</html>
